﻿namespace TfsReportRenderer.CommandLine
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Windows.Forms;

    using global::CommandLine;

    using Microsoft.Reporting.WinForms;

    /// <summary>
    /// The main program class.
    /// </summary>
    public static class Program
    {
        /// <summary>
        /// The main function of the program.
        /// </summary>
        /// <param name="args">
        /// The arguments - <see cref="Options"/>. 
        /// </param>
        [STAThread]
        public static void Main(string[] args)
        {
            var options = new Options();
            if (!Parser.Default.ParseArguments(args, options))
            {
                return;
            }

            var tfsContext = new TfsContext(new Uri(options.Url));

            var teamProject = !string.IsNullOrEmpty(options.Project) ? options.Project : tfsContext.TeamProjects.First();
            var selectedTestPlan = !string.IsNullOrEmpty(options.Plan) ? options.Plan : tfsContext.GetTestPlans(teamProject).First();

            var data = tfsContext.GetReportData(teamProject, selectedTestPlan, options.Date).ToArray();

            if (!data.Any())
            {
                Console.WriteLine("No test results found - cancelling report.");
                return;
            }

            var reportFile = GenerateFile(options, data);
            if (!string.IsNullOrEmpty(reportFile))
            {
                Process.Start(reportFile);
            }
        }

        /// <summary>Generates the requested file format.</summary>
        /// <param name="options">The processing options.</param>
        /// <param name="data">The data.</param>
        /// <returns>The <see cref="string"/>.</returns>
        private static string GenerateFile(Options options, IEnumerable<TestResultData> data)
        {
            switch (options.Renderer)
            {
                case SheetRenderer.Rdl:
                    return CreateReportFile(data, options.OutputFile, options.FileFormat, options.RdlFile);

                default:
                    return CreateExcelFile(data, options.OutputFile);
            }
        }

        /// <summary>
        /// The create report file.
        /// </summary>
        /// <param name="data"> The data to be rendered. </param>
        /// <param name="outputFile"> The output file. </param>
        /// <param name="outFormat"> The output file format (PDF/Excel). </param>
        /// <param name="rdlFile">The RDL file to use (default is embedded resource).</param>
        /// <returns> The path to the target file. </returns>
        private static string CreateReportFile(IEnumerable data, string outputFile, SheetFormat outFormat, string rdlFile)
        {
            var reportDataSource1 = new ReportDataSource();
            using (var testSuiteBindingSource = new BindingSource())
            using (var reportViewer = new ReportViewer())
            {
                reportDataSource1.Name = "DataSet1";
                reportDataSource1.Value = testSuiteBindingSource;
                reportViewer.LocalReport.DataSources.Add(reportDataSource1);
                if (string.IsNullOrEmpty(rdlFile))
                {
                    reportViewer.LocalReport.ReportEmbeddedResource = "TfsReportRenderer.CommandLine.Report1.rdlc";
                }
                else
                {
                    using (var fileStream = File.OpenRead(rdlFile))
                    {
                        reportViewer.LocalReport.LoadReportDefinition(fileStream);
                    }
                }

                testSuiteBindingSource.DataSource = data;
                Warning[] warnings;
                string[] streamids;
                string mimeType;
                string encoding;
                string extension;
                var bytes = reportViewer.LocalReport.Render(outFormat.ToString(), null, out mimeType, out encoding, out extension, out streamids, out warnings);

                var targetFile = !string.IsNullOrEmpty(outputFile) ? outputFile : "result." + extension;

                if (File.Exists(targetFile))
                {
                    try
                    {
                        File.Delete(targetFile);
                    }
                    catch (IOException ex)
                    {
                        Console.WriteLine("Cannot delete existing file [{0}] - message: [{1}]", targetFile, ex.Message);
                        return string.Empty;
                    }
                }

                using (var fs = new FileStream(targetFile, FileMode.Create))
                {
                    fs.Write(bytes, 0, bytes.Length);
                }

                return targetFile;
            }
        }

        /// <summary>
        /// Creates the excel file.
        /// </summary>
        /// <param name="data"> The data to be rendered. </param>
        /// <param name="outputFile"> The output path and file name (without file extension). </param>
        /// <returns> The target path and file name. </returns>
        private static string CreateExcelFile(IEnumerable<TestResultData> data, string outputFile)
        {
            var formatter = new ExcelFormatter();
            var targetFile = (!string.IsNullOrEmpty(outputFile) ? outputFile : "result") + ".xlsx";
            formatter.Write(data, targetFile);
            return targetFile;
        }
    }
}
